﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Markup;
using System.Windows.Media.Imaging;
using BrainTechLLC.ThreadSafeObjects;
using System.Threading;
using System.Windows.Threading;

namespace BrainTechLLC.Silverlight.Controls
{
    [TemplatePart(Name = "DescriptionText", Type = typeof(TextBlock))]
    [TemplatePart(Name = "NameSummary", Type = typeof(TextBlock))]
    [TemplatePart(Name = "ExpandButton", Type = typeof(Button))]
    [TemplatePart(Name = "EditButton", Type = typeof(Button))]
    [TemplatePart(Name = "SaveButton", Type = typeof(Button))]
    [TemplatePart(Name = "CloseButton2", Type = typeof(Button))]
    [TemplatePart(Name = "ShowCollapsed", Type = typeof(Border))]
    [TemplatePart(Name = "mainLayoutGrid", Type = typeof(Grid))]
    [TemplatePart(Name = "mainBorder", Type = typeof(Grid))]
    [TemplatePart(Name = "gridMain", Type = typeof(Grid))]
    [TemplatePart(Name = "indentFill", Type = typeof(Rectangle))]
    [TemplatePart(Name = "imgExpand", Type = typeof(Image))]
    [TemplatePart(Name = "imgClose", Type = typeof(Image))]
    [TemplatePart(Name = "imgEdit", Type = typeof(Image))]
    [TemplatePart(Name = "imgSave", Type = typeof(Image))]
    [TemplatePart(Name = "PART_Content", Type = typeof(ContentPresenter))]
    [TemplatePart(Name = "stacker", Type = typeof(StackPanel))]
    [TemplatePart(Name = "LeftSide", Type = typeof(Rectangle))]
    [TemplatePart(Name = "RightSide", Type = typeof(Rectangle))]
    [TemplatePart(Name = "BottomSide", Type = typeof(Rectangle))]
    [TemplatePart(Name = "TopSide", Type = typeof(Rectangle))]
    [TemplatePart(Name = "DragBar", Type = typeof(Rectangle))]
    [TemplatePart(Name = "CloseButtonBackground", Type = typeof(Rectangle))]
    public partial class WindowContainer : ContentControl, IUICanOpenClose, IUICanSave, IUICanEdit, IUICanHideHeader
    {
        [Flags]
        public enum ResizeType : byte
        {
            None = 0,
            ResizeLeft = 1,
            ResizeX = 2,
            ResizeY = 4
        }

        public static readonly BitmapImage expand = new BitmapImage(new Uri("/Symbol Expand Vertical.png", UriKind.Relative));
        public static readonly BitmapImage expand2 = new BitmapImage(new Uri("/Symbol Expand Vertical2.png", UriKind.Relative));
        public static readonly BitmapImage save = new BitmapImage(new Uri("/Save 2.png", UriKind.Relative));
        public static readonly BitmapImage edit2 = new BitmapImage(new Uri("/Symbol Edit 2.png", UriKind.Relative));
        public static readonly BitmapImage close = new BitmapImage(new Uri("/Symbol Delete 2.png", UriKind.Relative));
        public static readonly Brush BlackBrush = new SolidColorBrush(Colors.Black);

        public Func<WindowContainer, bool> FilterWindowlessMode { get; set; }
        public Func<WindowContainer, bool> FilterHideHeader { get; set; }

        private event EventHandler _closeWindow;

        public event EventHandler CloseWindow
        {
            add
            {
                CloseWindowListenerCount.Increment();
                lock (this)
                {
                    _closeWindow += value;
                }
            }
            remove
            {
                CloseWindowListenerCount.Decrement();
                lock (this)
                {
                    _closeWindow -= value;
                }
            }
        }

        protected ThreadSafeCounter CloseWindowListenerCount = new ThreadSafeCounter();
        public event EventHandler<ObjectEventArgsNonRef<bool>> WantClose;
        public event EventHandler<ObjectEventArgsNonRef<bool>> RequestSave;
        public event EventHandler Save;
        public Timer _timer;

        protected bool _setIsModal;
        protected bool _needsWindowlessModeUpdate;
        protected bool _needsUpdateHideHeader;
        protected Rectangle _indentFill;
        protected Point _mouseDownAt;
        protected ResizeType _resize;
        protected bool _updatedSaveButton;
        protected StackPanel _stacker;
        protected TextBlock _descriptionTextBlock;
        protected Button _expandButton;
        protected ContentPresenter _content;
        protected Button _editButton;
        protected Point StartingDragPoint;
        protected Button _saveButton;
        protected Button _closeButton;
        protected Image _imgExpand;
        protected Image _imgEdit;
        protected Image _imgSave;
        protected Image _imgClose;
        protected TextBlock _nameSummary;
        protected Grid _mainBorder;
        public Border _showCollapsed;
        protected Grid _mainLayoutGrid;
        protected Grid _gridMain;
        protected Rectangle LeftSide;
        protected Rectangle RightSide;
        protected Rectangle TopSide;
        protected Rectangle BottomSide;
        protected Rectangle DragBar;
        protected Point _pointStart = new Point();
        protected bool _shiftDown;

        public static Brush WhiteBrush = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
        public static Brush BrownBrush = new SolidColorBrush(Color.FromArgb(255, 186, 44, 44));
        public static Brush DefaultHeaderBrush = new SolidColorBrush(Color.FromArgb(255, 3, 6, 205));

        public WindowContainer Window { get { return this; } }

        public void OnWantClose(object sender, ObjectEventArgsNonRef<bool> e)
        {
            if (WantClose != null)
                WantClose(sender, e);
        }

        public void OnCloseWindow(object sender, EventArgs e)
        {
            if (_closeWindow != null)
                _closeWindow(sender, e);
        }

        public static void HandleChange<T2>(DependencyObject d, DependencyPropertyChangedEventArgs e, Action<WindowContainer, T2> action)
        {
            if (d != null)
                d.HandleChange<WindowContainer, T2>(e, action, (t) => t.Refresh());
        }

        public static readonly DependencyProperty DescriptionTextStringProperty = DependencyProperty.Register(
            "DescriptionTextString", typeof(string), typeof(WindowContainer), new PropertyMetadata("Description", new PropertyChangedCallback(DescriptionTextChanged)));

        public static readonly DependencyProperty UniqueStringProperty = DependencyProperty.Register(
            "UniqueString", typeof(string), typeof(WindowContainer), new PropertyMetadata("", new PropertyChangedCallback(UniqueChanged)));

        public static readonly DependencyProperty ContentBackgroundProperty = DependencyProperty.Register(
            "ContentBackground", typeof(Brush), typeof(WindowContainer), new PropertyMetadata(WhiteBrush, new PropertyChangedCallback(ContentBackgroundChanged)));

        public static readonly DependencyProperty WindowBorderProperty = DependencyProperty.Register(
            "WindowBorder", typeof(Brush), typeof(WindowContainer), new PropertyMetadata(BrownBrush, new PropertyChangedCallback(WindowBorderChanged)));

        public static readonly DependencyProperty HeaderBackgroundProperty = DependencyProperty.Register(
            "HeaderBackground", typeof(Brush), typeof(WindowContainer), new PropertyMetadata(DefaultHeaderBrush, new PropertyChangedCallback(HeaderBackgroundChanged)));

        public static readonly DependencyProperty WindowlessModeProperty = DependencyProperty.RegisterAttached(
            "WindowlessMode", typeof(bool), typeof(WindowContainer), new PropertyMetadata(false, new PropertyChangedCallback(WindowlessModeChanged)));

        public static readonly DependencyProperty IndentProperty = DependencyProperty.Register(
            "Indent", typeof(int), typeof(WindowContainer), new PropertyMetadata(0, new PropertyChangedCallback(IndentChanged)));

        public static readonly DependencyProperty IsOpenProperty = DependencyProperty.RegisterAttached(
            "IsOpen", typeof(bool), typeof(WindowContainer), new PropertyMetadata(true, new PropertyChangedCallback(OpenChanged)));

        public static readonly DependencyProperty HideHeaderProperty = DependencyProperty.RegisterAttached(
            "HideHeader", typeof(bool), typeof(WindowContainer), new PropertyMetadata(false, new PropertyChangedCallback(HideHeaderChanged)));

        public static readonly DependencyProperty ShowCloseProperty = DependencyProperty.RegisterAttached(
            "ShowClose", typeof(bool), typeof(WindowContainer), new PropertyMetadata(true, new PropertyChangedCallback(ShowCloseChanged)));

        public static readonly DependencyProperty ShowEditProperty = DependencyProperty.RegisterAttached(
            "ShowEdit", typeof(bool), typeof(WindowContainer), new PropertyMetadata(false, new PropertyChangedCallback(ShowEditChanged)));

        public static readonly DependencyProperty ShowSaveProperty = DependencyProperty.RegisterAttached(
            "ShowSave", typeof(bool), typeof(WindowContainer), new PropertyMetadata(true, new PropertyChangedCallback(ShowSaveChanged)));

        public static readonly DependencyProperty CenterScreenProperty = DependencyProperty.RegisterAttached(
            "CenterScreen", typeof(bool), typeof(WindowContainer), new PropertyMetadata(false, new PropertyChangedCallback(CenterScreenChanged)));

        public static readonly DependencyProperty IsModalProperty = DependencyProperty.RegisterAttached(
            "IsModal", typeof(bool), typeof(WindowContainer), new PropertyMetadata(false, new PropertyChangedCallback(IsModalChanged)));

        public static void SetWindowlessMode(UIElement element, Boolean value)
        {
            element.SetValue(WindowlessModeProperty, value);
        }

        public static bool GetWindowlessMode(UIElement element)
        {
            return (bool)element.GetValue(WindowlessModeProperty);
        }

        public bool WindowlessMode
        {
            get { return (bool)GetValue(WindowlessModeProperty); }
            set
            {
                if (WindowlessMode != value) _needsWindowlessModeUpdate = true;
                SetValue(WindowlessModeProperty, value);
            }
        }

        private static void WindowlessModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<bool>(d, e, (t, val) => t.WindowlessMode = val);
        }

        private static void ContentBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<Brush>(d, e, (t, val) => t.ContentBackground = val);
        }

        private static void WindowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<Brush>(d, e, (t, val) => t.WindowBorder = val);
        }

        private static void HeaderBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<Brush>(d, e, (t, val) => t.HeaderBackground = val);
        }

        public Brush ContentBackground
        {
            get { return (Brush)GetValue(ContentBackgroundProperty); }
            set { SetValue(ContentBackgroundProperty, value); }
        }

        public Brush WindowBorder
        {
            get { return (Brush)GetValue(WindowBorderProperty); }
            set { SetValue(WindowBorderProperty, value); }
        }

        public Brush HeaderBackground
        {
            get { return (Brush)GetValue(HeaderBackgroundProperty); }
            set { SetValue(HeaderBackgroundProperty, value); }
        }

        public static void SetShowClose(UIElement element, Boolean value)
        {
            element.SetValue(ShowCloseProperty, value);
        }

        public static bool GetShowClose(UIElement element)
        {
            return (bool)element.GetValue(ShowCloseProperty);
        }

        public static void SetShowEdit(UIElement element, Boolean value)
        {
            element.SetValue(ShowEditProperty, value);
        }

        public static bool GetShowEdit(UIElement element)
        {
            return (bool)element.GetValue(ShowEditProperty);
        }

        public static void SetShowSave(UIElement element, Boolean value)
        {
            element.SetValue(ShowSaveProperty, value);
        }

        public static bool GetShowSave(UIElement element)
        {
            return (bool)element.GetValue(ShowSaveProperty);
        }

        public static void SetCenterScreen(UIElement element, Boolean value)
        {
            element.SetValue(CenterScreenProperty, value);
        }

        public static bool GetCenterScreen(UIElement element)
        {
            return (bool)element.GetValue(CenterScreenProperty);
        }

        public static void SetIsModal(UIElement element, Boolean value)
        {
            element.SetValue(IsModalProperty, value);
        }

        public static bool GetIsModal(UIElement element)
        {
            return (bool)element.GetValue(IsModalProperty);
        }

        public static void SetIsOpen(UIElement element, Boolean value)
        {
            element.SetValue(IsOpenProperty, value);
        }

        public static bool GetIsOpen(UIElement element)
        {
            return (bool)element.GetValue(IsOpenProperty);
        }

        public static void SetHideHeader(UIElement element, Boolean value)
        {
            element.SetValue(HideHeaderProperty, value);
        }

        public static bool GetHideHeader(UIElement element)
        {
            return (bool)element.GetValue(HideHeaderProperty);
        }

        public int Indent
        {
            get { return (int)GetValue(IndentProperty); }
            set { SetValue(IndentProperty, value); }
        }

        public bool ShowClose
        {
            get { return (bool)GetShowClose(this); }
            set { SetShowClose(this, value); }
        }

        public bool ShowSave
        {
            get { return (bool)GetShowSave(this); }
            set { SetShowSave(this, value); }
        }

        public bool CenterScreen
        {
            get { return (bool)GetCenterScreen(this); }
            set { SetCenterScreen(this, value); }
        }

        public bool IsModal
        {
            get { return (bool)GetIsModal(this); }
            set { SetIsModal(this, value); }
        }

        public bool ShowEdit
        {
            get { return (bool)GetShowEdit(this); }
            set { SetShowEdit(this, value); }
        }

        private static void ShowCloseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            IUICanOpenClose c = d as IUICanOpenClose;
            if (c != null)
            {
                c.ShowClose = (bool)e.NewValue;
                c.Refresh();
            }
        }

        private static void ShowEditChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            IUICanEdit c = d as IUICanEdit;
            if (c != null)
            {
                c.ShowEdit = (bool)e.NewValue;
                c.Refresh();
            }
        }

        private static void ShowSaveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            IUICanSave c = d as IUICanSave;
            if (c != null)
            {
                c.ShowSave = (bool)e.NewValue;
                c.Refresh();
            }
        }

        private static void IsModalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ICanPosition c = d as ICanPosition;
            if (c != null)
            {
                c.IsModal = (bool)e.NewValue;
                c.Refresh();
            }
        }

        private static void CenterScreenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ICanPosition c = d as ICanPosition;
            if (c != null)
            {
                c.CenterScreen = (bool)e.NewValue;
                c.Refresh();
            }
        }

        public string DescriptionTextString
        {
            get { return (string)GetValue(DescriptionTextStringProperty); }
            set { SetValue(DescriptionTextStringProperty, value); }
        }

        public string UniqueString
        {
            get { return (string)GetValue(UniqueStringProperty); }
            set { SetValue(UniqueStringProperty, value); }
        }

        private static void DescriptionTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<string>(d, e, (t, val) => t.DescriptionTextString = val);
        }

        private static void UniqueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<string>(d, e, (t, val) => t.UniqueString = val);
        }

        public bool IsOpen
        {
            get { return (bool)GetIsOpen(this); }
            set { SetIsOpen(this, value); }
        }

        private static void OpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            IUICanOpenClose t = d as IUICanOpenClose;
            if (t != null)
            {
                bool newOpen = (bool)e.NewValue;
                t.IsOpen = newOpen;
                t.Refresh();
            }
        }

        public bool HideHeader
        {
            get { return (bool)GetHideHeader(this); }
            set
            {
                _needsUpdateHideHeader = true;
                SetHideHeader(this, value);
            }
        }

        private static void HideHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            IUICanHideHeader t = d as IUICanHideHeader;
            if (t != null)
            {
                bool hideHeader = (bool)e.NewValue;
                t.HideHeader = hideHeader;
                t.Refresh();
            }
        }

        public virtual void Refresh()
        {
            if (_showCollapsed != null)
            {
                if (_showCollapsed.EnsureVisibility(IsOpen))
                {
                    if (_shiftDown)
                    {
                        (_content.Content as Control).ForEachRecursive<WindowContainer>((wc) => wc.IsOpen = IsOpen, null);
                    }
                }
            }

            if (_closeButton != null)
            {
                if (ShowClose && CloseWindowListenerCount.Count == 0)
                {
                    _closeButton.Visibility = Visibility.Collapsed;
                }
                else if (!ShowClose && CloseWindowListenerCount.Count > 0)
                {
                    _closeButton.Visibility = Visibility.Visible;
                }
            }

            if (_editButton != null)
                _editButton.EnsureVisibility(ShowEdit);

            if (_saveButton != null)
            {
                if (_saveButton.EnsureVisibility(ShowSave))
                {
                    _updatedSaveButton = true;
                }
            }

            if (_descriptionTextBlock != null && DescriptionTextString != null)
                _descriptionTextBlock.Text = DescriptionTextString;

            if (_mainLayoutGrid != null && _mainLayoutGrid.ColumnDefinitions.Count > 0 && _mainLayoutGrid.ColumnDefinitions[0].Width.Value != (Indent * 8))
            {
                _mainLayoutGrid.ColumnDefinitions[0].Width = new GridLength((Indent * 8), GridUnitType.Pixel);
                _indentFill.Fill = HeaderBackground;
            }

            if (_imgExpand != null)
            {
                if (IsOpen && _imgExpand.Source != expand)
                {
                    _imgExpand.Source = expand;
                }
                else if (!IsOpen && _imgExpand.Source != expand2)
                {
                    _imgExpand.Source = expand2;
                }
            }

            if (_needsUpdateHideHeader && _mainBorder != null)
            {
                _needsUpdateHideHeader = false;

                if (HideHeader)
                {
                    DoHideHeader();
                }
                else if (!HideHeader)
                {
                    DoShowHeader();
                }

                if (FilterHideHeader != null)
                {
                    (_content.Content as Control).ForEachRecursive<WindowContainer>((wc) =>
                    {
                        if (wc.FilterHideHeader == null)
                            wc.FilterHideHeader = FilterHideHeader;
                    }, null);

                    (_content.Content as Control).ForEachRecursive<WindowContainer>((wc) => wc.HideHeader = HideHeader, FilterHideHeader);
                }
            }

            if (_needsWindowlessModeUpdate && _mainBorder != null)
            {
                _needsWindowlessModeUpdate = false;
                if (WindowlessMode)
                {
                    _mainLayoutGrid.Margin = new Thickness(0, 2, 0, 0);
                    _showCollapsed.BorderThickness = new Thickness(0, 2, 0, 0);
                }
                else
                {
                    _mainLayoutGrid.Margin = new Thickness(3, 3, 3, 3);
                    _showCollapsed.BorderThickness = new Thickness(0, 3, 0, 0);
                }

                if (FilterWindowlessMode != null)
                {
                    (_content.Content as Control).ForEachRecursive<WindowContainer>((wc) =>
                    {
                        if (wc.FilterWindowlessMode == null)
                            wc.FilterWindowlessMode = FilterWindowlessMode;
                    }, null);

                    (_content.Content as Control).ForEachRecursive<WindowContainer>((wc) => wc.WindowlessMode = WindowlessMode, FilterWindowlessMode);
                }
            }

            if (_mainBorder != null)
            {
                if (IsModal && !_setIsModal)
                {
                    // Not working
                    _setIsModal = true;
                    //var par = VisualTreeHelper.GetParent(this);
                    //par = VisualTreeHelper.GetParent(par);
                    //SetEnabled(par as UIElement, false, this as Control, true);
                }
            }
        }

        public void SetEnabled(UIElement c, bool enabled, Control except, bool skipFirst)
        {
            Control ct = c as Control;

            if (!skipFirst && ct != null)
                ct.IsEnabled = enabled;

            skipFirst = false;

            for (int n = 0; n < VisualTreeHelper.GetChildrenCount(c); n++)
            {
                var ctrl = VisualTreeHelper.GetChild(c, n);

                if (ctrl == this)
                {
                    SetEnabled(ctrl as UIElement, true, ctrl as Control, skipFirst);
                    continue;
                }

                if (ctrl is UIElement)
                    SetEnabled(ctrl as UIElement, enabled, except, skipFirst);
            }
        }

        private void DoShowHeader()
        {
            _descriptionTextBlock.Visibility = Visibility.Visible;
            _stacker.Visibility = Visibility.Visible;
            _nameSummary.Visibility = Visibility.Visible;
            _mainLayoutGrid.RowDefinitions[0].Height = new GridLength(18, GridUnitType.Pixel);
            _mainLayoutGrid.Margin = new Thickness(3, 3, 3, 3);
            _needsWindowlessModeUpdate = true;
        }

        private void DoHideHeader()
        {
            _descriptionTextBlock.Visibility = Visibility.Collapsed;
            _stacker.Visibility = Visibility.Collapsed;
            _nameSummary.Visibility = Visibility.Collapsed;
            _showCollapsed.BorderThickness = new Thickness(0, 0, 0, 0);
            _mainLayoutGrid.Margin = new Thickness(3, 0, 3, 0);
            _mainLayoutGrid.RowDefinitions[0].Height = new GridLength(0, GridUnitType.Pixel);
            IsOpen = true;
        }

        private static void IndentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<int>(d, e, (t, val) => t.Indent = val);
        }

        ~WindowContainer()
        {
        }

        public WindowContainer()
            : base()
        {
            DefaultStyleKey = typeof(WindowContainer);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            FindAllControls();
            _imgSave.Source = save;
            _imgEdit.Source = edit2;
            _imgClose.Source = close;
            _imgExpand.Source = expand;
            _descriptionTextBlock.MouseLeftButtonDown += new MouseButtonEventHandler(_descriptionTextBlock_MouseLeftButtonDown);

            _expandButton.Click += new RoutedEventHandler(_expandButton_Click);
            _editButton.Click += new RoutedEventHandler(_editButton_Click);
            _saveButton.Click += new RoutedEventHandler(_saveButton_Click);

            _closeButton.Click += new RoutedEventHandler(_closeButton_Click);

            LeftSide.MouseLeftButtonDown += new MouseButtonEventHandler(LeftSide_MouseLeftButtonDown);
            RightSide.MouseLeftButtonDown += new MouseButtonEventHandler(RightSide_MouseLeftButtonDown);
            TopSide.MouseLeftButtonDown += new MouseButtonEventHandler(TopSide_MouseLeftButtonDown);
            BottomSide.MouseLeftButtonDown += new MouseButtonEventHandler(BottomSide_MouseLeftButtonDown);
            DragBar.MouseLeftButtonDown += new MouseButtonEventHandler(DragBar_MouseLeftButtonDown);

            _mainBorder.Cursor = Cursors.Hand;

            KeyDown += new KeyEventHandler(WindowContainer_KeyDown);
            KeyUp += new KeyEventHandler(WindowContainer_KeyUp);

            _timer = new Timer(new TimerCallback(_timer_Tick), null, 200, UInt32.MaxValue);

            Refresh();
        }


        void _timer_Tick(object o)
        {
            _timer.Dispose();
            _timer = null;

            Dispatcher.BeginInvoke(() =>
            {
                if (_mainBorder != null && CenterScreen && this.ActualWidth > 10 && this.ActualHeight > 10)
                {
                    var left = (Application.Current.Host.Content.ActualWidth - this.ActualWidth) / 2;
                    var top = (Application.Current.Host.Content.ActualHeight - this.ActualHeight) / 2;

                    if (_mainBorder.Margin == null || _mainBorder.Margin.Left != left)
                        _mainBorder.Margin = new Thickness(left, top - 20, 0, 0);
                }
            });
        }

        void _descriptionTextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var y = e.GetPosition(sender as UIElement).Y;

            if (y <= 18 && y >= 3)
            {
                _expandButton_Click(sender, e);
                e.Handled = true;
            }
        }

        void _stacker_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _expandButton_Click(sender, e);
        }

        private void FindAllControls()
        {
            _descriptionTextBlock = base.GetTemplateChild("DescriptionText") as TextBlock;
            _expandButton = base.GetTemplateChild("ExpandButton") as Button;
            _editButton = base.GetTemplateChild("EditButton") as Button;
            _saveButton = base.GetTemplateChild("SaveButton") as Button;
            _closeButton = base.GetTemplateChild("CloseButton2") as Button;
            _nameSummary = base.GetTemplateChild("NameSummary") as TextBlock;
            _showCollapsed = base.GetTemplateChild("ShowCollapsed") as Border;
            _mainLayoutGrid = base.GetTemplateChild("mainLayoutGrid") as Grid;
            _mainBorder = base.GetTemplateChild("mainBorder") as Grid;
            _gridMain = base.GetTemplateChild("gridMain") as Grid;
            _indentFill = base.GetTemplateChild("indentFill") as Rectangle;
            _imgExpand = base.GetTemplateChild("imgExpand") as Image;
            _imgClose = base.GetTemplateChild("imgClose") as Image;
            _imgEdit = base.GetTemplateChild("imgEdit") as Image;
            _imgSave = base.GetTemplateChild("imgSave") as Image;
            _content = base.GetTemplateChild("PART_Content") as ContentPresenter;
            _stacker = base.GetTemplateChild("stacker") as StackPanel;
            LeftSide = base.GetTemplateChild("LeftSide") as Rectangle;
            RightSide = base.GetTemplateChild("RightSide") as Rectangle;
            TopSide = base.GetTemplateChild("TopSide") as Rectangle;
            BottomSide = base.GetTemplateChild("BottomSide") as Rectangle;
            DragBar = base.GetTemplateChild("DragBar") as Rectangle;
        }

        void WindowContainer_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Shift)
                _shiftDown = false;
        }

        void WindowContainer_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Shift)
                _shiftDown = true;
        }


        void _saveButton_Click(object sender, RoutedEventArgs e)
        {
            ObjectEventArgsNonRef<bool> args = new ObjectEventArgsNonRef<bool>();

            if (RequestSave != null)
            {
                RequestSave(this, args);
            }

            if (args.obj != true && Save != null)
            {
                Save(this, args);
            }
        }

        void _editButton_Click(object sender, RoutedEventArgs e)
        {
            // TODO
        }

        void _closeButton_Click(object sender, RoutedEventArgs e)
        {
            ObjectEventArgsNonRef<bool> args = new ObjectEventArgsNonRef<bool>();

            if (WantClose != null)
                WantClose(this, args);

            if (args.obj != true && _closeWindow != null)
            {
                _closeWindow(this, args);
            }
        }

        void _expandButton_Click(object sender, RoutedEventArgs e)
        {
            IsOpen = !IsOpen;
        }

        private void DragBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            MoveToTop();

            //Start Drag
            FrameworkElement DragBar = (FrameworkElement)sender;
            DragBar.CaptureMouse();

            // Set the starting point for the drag
            StartingDragPoint = e.GetPosition(DragBar);

            DragBar.MouseMove += new MouseEventHandler(DragBar_MouseMove);
            DragBar.MouseLeftButtonUp += new MouseButtonEventHandler(DragBar_MouseLeftButtonUp);
        }

        private void MoveToTop()
        {
            UIElement par = (UIElement)this.Parent;

            //Find the highest elemnt
            int intHighestElement = 0;
            for (int n = 0; n < VisualTreeHelper.GetChildrenCount(par); n++)
            {
                UIElement UIElement = VisualTreeHelper.GetChild(par, n) as UIElement;
                if (UIElement != null)
                {
                    int intTmpHighestElement = Canvas.GetZIndex(UIElement);
                    intHighestElement = (intTmpHighestElement > intHighestElement) ? intTmpHighestElement : intHighestElement;
                }
            }

            Canvas.SetZIndex(this, intHighestElement + 1);
        }

        private void DragBar_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //Stop Drag
            FrameworkElement DragBar = (FrameworkElement)sender;
            DragBar.ReleaseMouseCapture();

            DragBar.MouseMove -= new MouseEventHandler(DragBar_MouseMove);
            DragBar.MouseLeftButtonUp -= new MouseButtonEventHandler(DragBar_MouseLeftButtonUp);
        }

        private void DragBar_MouseMove(object sender, MouseEventArgs e)
        {
            UIElement par = (UIElement)this.Parent;
            Point Point = e.GetPosition(par);

            // Do not allow drag past the top or the left of the screen
            if (Point.Y < 0)
            {
                Point.Y = 0;
                return;
            }

            if (Point.X < 0)
            {
                Point.X = 0;
                return;
            }

            _mainBorder.Margin = new Thickness(Point.X - StartingDragPoint.X, Point.Y - StartingDragPoint.Y, 0, 0);
        }

        #region RightSide
        private void RightSide_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //Start Drag
            FrameworkElement RightSide = (FrameworkElement)sender;
            RightSide.CaptureMouse();

            // Set the starting point for the drag
            StartingDragPoint = e.GetPosition(null);

            RightSide.MouseMove += new MouseEventHandler(RightSide_MouseMove);
            RightSide.MouseLeftButtonUp += new MouseButtonEventHandler(RightSide_MouseLeftButtonUp);
        }

        void RightSide_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //Stop Drag
            FrameworkElement RightSide = (FrameworkElement)sender;
            RightSide.ReleaseMouseCapture();

            RightSide.MouseMove -= new MouseEventHandler(RightSide_MouseMove);
            RightSide.MouseLeftButtonUp -= new MouseButtonEventHandler(RightSide_MouseLeftButtonUp);
        }

        void RightSide_MouseMove(object sender, MouseEventArgs e)
        {
            Point Point = e.GetPosition(null);
            _mainBorder.Width = _mainBorder.ActualWidth + ((double)(Point.X - StartingDragPoint.X));
            StartingDragPoint = Point;
        }
        #endregion

        #region LeftSide
        private void LeftSide_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //Start Drag
            FrameworkElement LeftSide = (FrameworkElement)sender;
            LeftSide.CaptureMouse();

            // Set the starting point for the drag
            StartingDragPoint = e.GetPosition(null);
            Point ControlPoint = e.GetPosition(this);

            LeftSide.MouseMove += new MouseEventHandler(LeftSide_MouseMove);
            LeftSide.MouseLeftButtonUp += new MouseButtonEventHandler(LeftSide_MouseLeftButtonUp);
        }

        void LeftSide_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //Stop Drag
            FrameworkElement LeftSide = (FrameworkElement)sender;
            LeftSide.ReleaseMouseCapture();

            LeftSide.MouseMove -= new MouseEventHandler(LeftSide_MouseMove);
            LeftSide.MouseLeftButtonUp -= new MouseButtonEventHandler(LeftSide_MouseLeftButtonUp);
        }

        void LeftSide_MouseMove(object sender, MouseEventArgs e)
        {
            Point Point = e.GetPosition(null);

            _mainBorder.Width = _mainBorder.ActualWidth + (StartingDragPoint.X - Point.X);
            _mainBorder.Margin = new Thickness(_mainBorder.Margin.Left + (Point.X - StartingDragPoint.X), _mainBorder.Margin.Top, 0, 0);

            StartingDragPoint = Point;
        }
        #endregion

        #region BottomSide
        private void BottomSide_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //Start Drag
            FrameworkElement BottomSide = (FrameworkElement)sender;
            BottomSide.CaptureMouse();

            // Set the starting point for the drag
            StartingDragPoint = e.GetPosition(null);

            BottomSide.MouseMove += new MouseEventHandler(BottomSide_MouseMove);
            BottomSide.MouseLeftButtonUp += new MouseButtonEventHandler(BottomSide_MouseLeftButtonUp);
        }

        void BottomSide_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //Stop Drag
            FrameworkElement BottomSide = (FrameworkElement)sender;
            BottomSide.ReleaseMouseCapture();

            BottomSide.MouseMove -= new MouseEventHandler(BottomSide_MouseMove);
            BottomSide.MouseLeftButtonUp -= new MouseButtonEventHandler(BottomSide_MouseLeftButtonUp);
        }

        void BottomSide_MouseMove(object sender, MouseEventArgs e)
        {
            Point Point = e.GetPosition(null);
            _mainBorder.Height = _mainBorder.ActualHeight + ((double)Point.Y - (StartingDragPoint.Y));
            StartingDragPoint = Point;
        }
        #endregion

        #region TopSide
        private void TopSide_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //Start Drag
            FrameworkElement TopSide = (FrameworkElement)sender;
            TopSide.CaptureMouse();

            // Set the starting point for the drag
            StartingDragPoint = e.GetPosition(null);
            Point ControlPoint = e.GetPosition(this);

            TopSide.MouseMove += new MouseEventHandler(TopSide_MouseMove);
            TopSide.MouseLeftButtonUp += new MouseButtonEventHandler(TopSide_MouseLeftButtonUp);
        }

        void TopSide_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //Stop Drag
            FrameworkElement TopSide = (FrameworkElement)sender;
            TopSide.ReleaseMouseCapture();

            TopSide.MouseMove -= new MouseEventHandler(TopSide_MouseMove);
            TopSide.MouseLeftButtonUp -= new MouseButtonEventHandler(TopSide_MouseLeftButtonUp);
        }

        void TopSide_MouseMove(object sender, MouseEventArgs e)
        {
            Point Point = e.GetPosition(null);

            _mainBorder.Height = _mainBorder.ActualHeight + (StartingDragPoint.Y - Point.Y);
            _mainBorder.Margin = new Thickness(_mainBorder.Margin.Left, _mainBorder.Margin.Top - (StartingDragPoint.Y - Point.Y), 0, 0);

            StartingDragPoint = Point;
        }
        #endregion
    }
}




//void _mainBorder_MouseLeave(object sender, MouseEventArgs e)
//{
//    if (_mainBorder != null)
//        _mainBorder.Cursor = Cursors.Hand;
//}

//void _mainBorder_MouseEnter(object sender, MouseEventArgs e)
//{
//    if (_mainBorder != null)
//    {
//        _mouseDownAt = e.GetPosition(_mainBorder);
//        ResizeType resize;
//        DetermineResize(out resize);

//        if (((resize & ResizeType.ResizeX) == ResizeType.ResizeX) &&
//            ((resize & ResizeType.ResizeY) == ResizeType.ResizeY))
//            _mainBorder.Cursor = Cursors.Stylus;
//        else if ((resize & ResizeType.ResizeX) == ResizeType.ResizeX)
//            _mainBorder.Cursor = Cursors.SizeWE;
//        else if ((resize & ResizeType.ResizeY) == ResizeType.ResizeY)
//            _mainBorder.Cursor = Cursors.SizeNS;
//        else
//            _mainBorder.Cursor = Cursors.Hand;
//    }
//}

//void _mainBorder_MouseMove(object sender, MouseEventArgs e)
//{
//    if (_mainBorder != null)
//    {
//        if (_pointStart.X == 0)
//        {
//            _mouseDownAt = e.GetPosition(_mainBorder);
//            ResizeType resize;
//            DetermineResize(out resize);

//            if ((resize & ResizeType.ResizeX) == ResizeType.ResizeX)
//                _mainBorder.Cursor = Cursors.SizeWE;
//            else if ((resize & ResizeType.ResizeY) == ResizeType.ResizeY)
//                _mainBorder.Cursor = Cursors.SizeNS;
//            else
//                _mainBorder.Cursor = Cursors.Hand;

//            return;
//        }

//        Point now = e.GetPosition(null);
//        double dx = _pointStart.X - now.X;
//        double dy = _pointStart.Y - now.Y;

//        if ((_resize & ResizeType.ResizeX) == ResizeType.ResizeX)
//        {
//            double newWidth = ((_resize & ResizeType.ResizeLeft) == ResizeType.ResizeLeft) ?
//                                (_mainBorder.ActualWidth + dx) : (_mainBorder.ActualWidth - dx);

//            _mainBorder.Width = newWidth < 60 ? 60 : newWidth;
//        }

//        if ((_resize & ResizeType.ResizeY) == ResizeType.ResizeY)
//        {
//            double newHeight = _mainBorder.ActualHeight - dy;
//            _mainBorder.Height = newHeight < 30 ? 30 : newHeight;
//        }

//        if ((_resize & ResizeType.ResizeLeft) == ResizeType.ResizeLeft)
//        {
//            _mainBorder.Margin = new Thickness(_mainBorder.Margin.Left - dx, _mainBorder.Margin.Top, 0, 0);
//        }

//        if ((_resize & (ResizeType.ResizeX | ResizeType.ResizeY)) == 0)
//        {
//            _mainBorder.Margin = new Thickness(_mainBorder.Margin.Left - dx, _mainBorder.Margin.Top - dy, 0, 0);
//        }
//        else
//        {
//            DependencyObject parent = VisualTreeHelper.GetParent(this);
//            if (parent != null)
//            {
//                parent = VisualTreeHelper.GetParent(this);
//                if (parent != null)
//                {
//                    (parent as UIElement).UpdateLayout();
//                }
//            }
//        }

//        _pointStart = now;
//    }
//}

//void _mainBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
//{
//    if (_mainBorder != null)
//    {
//        if (IsEnabled)
//        {
//            Point pointEnd = e.GetPosition(null);
//            _pointStart.X = 0;
//            _pointStart.Y = 0;
//            _resize = ResizeType.None;
//            _mainBorder.ReleaseMouseCapture();
//            e.Handled = true;
//        }
//    }
//}

//void DetermineResize(out ResizeType resize)
//{
//    resize = ResizeType.None;

//    if (_mainBorder != null)
//    {
//        resize = ResizeType.None;
//        double height = _mainBorder.ActualHeight;
//        double width = _mainBorder.ActualWidth;

//        if (_mouseDownAt.Y > 24)
//        {
//            if (_mouseDownAt.X < 4)
//            {
//                resize |= (ResizeType.ResizeLeft | ResizeType.ResizeX);
//            }
//            if (_mouseDownAt.Y > height - 4)
//            {
//                resize |= ResizeType.ResizeY;
//            }
//            if (_mouseDownAt.X > width - 4)
//            {
//                resize |= ResizeType.ResizeX;
//            }
//        }
//    }
//}

//void _mainBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
//{
//    if (_mainBorder != null && IsEnabled)
//    {
//        _mouseDownAt = e.GetPosition(_mainBorder);
//        DetermineResize(out _resize);

//        _pointStart = e.GetPosition(null);
//        _mainBorder.CaptureMouse();
//        e.Handled = true;
//    }
//}



